using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using NHibernate;
using FluentNHibernate.Cfg;
using FluentNHibernate.Cfg.Db;
using NHibernate.Cfg;
using NHibernate.Tool.hbm2ddl;
using NHibernate.Linq;
using MoleCart.Core.Common;
using MoleCart.Core.Data;
using MoleCart.Core;
using MoleCart.Core.Domain;


namespace MoleCart.Data {
	public abstract class RepositoryBase<T> :  NHBase<T>, IRepository<T> where T : EntityBase {

		public RepositoryBase() : base(Const.CONNNAME_DEFAULT) { 
            _session = SessionFactory.OpenSession();
        }
		public RepositoryBase(string connectionStringName) : base(connectionStringName) { 
            _session = SessionFactory.OpenSession();
        }

        protected ISession _session = null;
        protected ITransaction _transaction = null;

        #region Transaction and Session Management Methods

        public void BeginTransaction()
        {
            _transaction = _session.BeginTransaction();
        }

        public void CommitTransaction()
        {
            // _transaction will be replaced with a new transaction
            // by NHibernate, but we will close to keep a consistent state.
            _transaction.Commit();

            CloseTransaction();
        }

        public void RollbackTransaction()
        {
            // _session must be closed and disposed after a transaction
            // rollback to keep a consistent state.
            _transaction.Rollback();

            CloseTransaction();
            CloseSession();
        }

        private void CloseTransaction()
        {
            _transaction.Dispose();
            _transaction = null;
        }

        private void CloseSession()
        {
            _session.Close();
            _session.Dispose();
            _session = null;
        }

        #endregion

        #region IDisposable Members

        public void Dispose()
        {
            if (_transaction != null)
            {
                // Commit transaction by default, unless user explicitly rolls it back.
                // To rollback transaction by default, unless user explicitly commits,
                // comment out the line below.
                CommitTransaction();
            }

            if (_session != null)
            {
                _session.Flush(); // commit session transactions
                CloseSession();
            }
        }

        #endregion

		public object Insert(T entity) {
            var id = _session.Save(entity);
			_session.Flush();
			return id;
		}

		public void Update(T entity) {
			_session.Update(entity);
			_session.Flush();
		}

		public void Delete(T entity) {
			_session.Delete(entity);
			_session.Flush();			
		}

		/// <summary>
		/// 实时加载
		/// </summary>
		/// <param name="id"></param>
		/// <returns></returns>
		public T GetById(object id) {			
			return _session.Get<T>(id);			
		}
		/// <summary>
		/// 延时加载
		/// </summary>
		/// <param name="id"></param>
		/// <returns></returns>
		public T LoadById(object id) {			
			return _session.Load<T>(id);
		}

		public virtual IList<T> GetAll() {
				return _session.Query<T>().ToList();
		}

		public virtual PaginatedList<T> GetAll(int pageIndex, int pageSize) {
				int count = _session.Query<T>().Count();
				IList<T> list = _session.Query<T>().Skip((pageIndex - 1) * pageSize).Take(pageSize).ToList();                
				PaginatedList<T> result = new PaginatedList<T>(pageIndex, pageSize, count);
				result.AddRange(list); 
				return result;
		}

		public virtual PaginatedList<T> GetAll<Tkey>(int pageIndex, int pageSize, System.Linq.Expressions.Expression<Func<T, bool>> where = null, System.Linq.Expressions.Expression<Func<T, Tkey>> order = null, SortType type= SortType.Asc) {
				int count = 0;
				IList<T> list;
				if (where == null && order == null) {
					count = _session.Query<T>().Count();
					list = _session.Query<T>().Skip((pageIndex - 1) * pageSize).Take(pageSize).ToList();
				}
				else if (where != null && order == null) {
					count = _session.Query<T>().Where(where).Count();
					list = _session.Query<T>().Where(where).Skip((pageIndex - 1) * pageSize).Take(pageSize).ToList();
				}
				else if (where == null && order != null) {
					count = _session.Query<T>().Count();
					if (type == SortType.Asc) {
						list = _session.Query<T>().OrderBy(order).Skip((pageIndex - 1) * pageSize).Take(pageSize).ToList();
					}
					else {
						list = _session.Query<T>().OrderByDescending(order).Skip((pageIndex - 1) * pageSize).Take(pageSize).ToList();
					}
				}
				else  {
					count = _session.Query<T>().Where(where).Count();
					if (type == SortType.Asc) {
						list = _session.Query<T>().Where(where).OrderBy(order).Skip((pageIndex - 1) * pageSize).Take(pageSize).ToList();
					}
					else {
						list = _session.Query<T>().Where(where).OrderByDescending(order).Skip((pageIndex - 1) * pageSize).Take(pageSize).ToList();
					} 
				}

				PaginatedList<T> result = new PaginatedList<T>(pageIndex, pageSize, count);
				result.AddRange(list);
				return result;
		}


	}


}
